package in

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"strings"

	csvmap "github.com/recursionpharma/go-csv-map"
)

// TextBottle init from text://[path]
type TextBottle struct {
	Bottle
}

// NewTextBottle init from text://[path]
func NewTextBottle(infoSchema string) (bottle *TextBottle, err error) {
	if !strings.HasPrefix(infoSchema, "text://") {
		err = errors.New("not valid text schema:" + infoSchema)
		return
	}
	bottle = new(TextBottle)
	bottle.Data = infoSchema
	bottle = new(TextBottle)
	bottle.Tp = "text"
	bottle.Engine = strings.SplitN(infoSchema, "text://", 2)[1]
	bottle.IsFile = true
	return
}

// Desc get csv header !
func (text *TextBottle) Desc(oper *Oper) (keys S) {
	fileName := text.Engine.(string)
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatal(err)
	}
	if oper.Sep == ""{
		oper.Sep = ","
	}
	buf := bytes.NewBuffer(data)
	reader := csvmap.NewReader(buf)
	reader.Reader.Comma = rune(oper.Sep[0])
	keys, err = reader.ReadHeader()
	return
}

func (mdb *TextBottle) GetTp() string {
	return mdb.Tp
}

func (text *TextBottle) GetName() string {
	return text.Data
}

// Query query by filter
func (text *TextBottle) Query(oper *Oper) (datas Datas) {
	defer func() {
		if len(GlobalOperChannel) > 0 {
			<-GlobalOperChannel
		}
	}()
	if oper.Sep == ""{
		oper.Sep = ","
	}
	GlobalOperChannel <- 0
	fileName := text.Engine.(string)
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatal(err)
	}
	buf := bytes.NewBuffer(data)
	reader := csvmap.NewReader(buf)
	reader.Reader.Comma = rune(oper.Sep[0])
	reader.Columns, err = reader.ReadHeader()

	filter := oper.Filter

	startAt := oper.Page * oper.Len
	endAt := startAt + oper.Len
	co := 0
	for {
		record, err := reader.Read()
		if err != nil {
			if fmt.Sprint(err) != "EOF" {
				log.Println(err)
			}
			break
		}
		if len(filter) > 0 {
			ifJumpt := false
			for fK, fV := range filter {
				if v, ok := record[fK]; !ok || !strings.Contains(fmt.Sprint(v), fmt.Sprint(fV)) {
					ifJumpt = true
					break
				}
			}
			if ifJumpt {
				continue
			}
		}
		if co >= startAt && co < endAt {
			data := make(G)
			for k, v := range record {
				data[k] = v
			}
			datas = append(datas, data)
		}
		co++
	}
	if !text.NoCached {
		SaveInCache(text.Data+"/"+oper.Name, datas)
	}
	return
}
